package MapperModule

import (
	"reflect"
	"errors"
	"frame/utils/StringUtils"
	"fmt"
	"frame/utils/FileUtils"
	"gdbc/gdbc/MapperXmlUtils"
	"frame/utils/XmlUtils"
	"regexp"
	"strings"
	"strconv"
	"frame/utils/PropertiesUtils"
)
/**
低配版本：词法解析器+语法解析器+文法解析器................
详见MapperXmlUtils.go
 */
/**
SQL缓存，key为:   MapperName:methodName
 */
var execsqls map[string]string = make(map[string]string)

//获取xml路径
func GetMapperXmlPath() (string) {
	var mapperXmlPath, _ = PropertiesUtils.GetConfig("gdbc", "mapperXmlPath", "gdbc")
	return mapperXmlPath
}

/**
param分为三种情况
1)结构体			不支持动态指令
2)数组或切片		不支持动态指令
3)Map			支持动态指令
 */
func getExecSql(mappermodule MapperModule, method string,param interface{}) (string, bool) {
	var mapperXmlPath = GetMapperXmlPath()
	var mappername = mappermodule.MapperName
	var sqlcontent = ""
	var found = false;

	//0 加载xml文件
	var realfilepath = mapperXmlPath + FileUtils.GetFileSeparator() + mappername + ".xml"
	var mapperXmlContent, err = FileUtils.ReadFile(realfilepath)
	if (err != nil) {
		logger.Error("解析Mapper.xml文件[" + realfilepath + "]异常，错误信息为[" + err.Error() + "]")
		//panic(err)
	}
	//fmt.Println(reflect.TypeOf(param).Kind())
	switch reflect.TypeOf(param).Kind() {
	case reflect.Map:
		//MAP支持动态指令
		//logger.Info("mapperXmlContent:"+mapperXmlContent)
		var parseResult bool
		var err error
		var returnresullt string
		if parseResult, err, returnresullt = MapperXmlUtils.ParseMapper(mapperXmlContent,method,param.(map[string]interface{})); !parseResult {
			logger.Error("解析Mapper.xml文件[" + realfilepath + "]异常，错误信息为[" + err.Error() + "]")
			//panic(err)
		}
		return returnresullt,true
	case reflect.Struct,reflect.Array,reflect.Slice:
		//不支持动态指令
		//logger.Info("mapperXmlContent:"+mapperXmlContent)
		var result = XmlUtils.Result{}
		if parseResult, err := XmlUtils.Parse(mapperXmlContent, &result); !parseResult {
			logger.Error("解析Mapper.xml文件[" + realfilepath + "]异常，错误信息为[" + err.Error() + "]")
			//panic(err)
		}
		var sqlstoken = result.Root.Tokens
	GETEXCELCONTENTOUT_UNMAP:
		for _, v := range sqlstoken {
			var attrs = v.Attributes
			for _, attr := range attrs {
				if (attr.Name == "id") {
					//fmt.Println("attr.Name="+attr.Name)
					if (attr.Value == method) {
						sqlcontent = StringUtils.Trim(XmlUtils.GetContentFromToken(&v))
						break GETEXCELCONTENTOUT_UNMAP
					}
				}
			}
		}
	default:
		logger.Error("解析Mapper.xml文件[" + realfilepath + "]异常，参数类型不正确，只允许为Map,struct,Array,slice")
	}

	logger.Debug("xmlsql  :    " + sqlcontent)
	return sqlcontent, found;
}


func parseParameter(execsql string , param interface{})(string,[]interface{},error){
	var args[]interface{}
	//组装参数
	if(param!=nil){
		switch reflect.TypeOf(param).Kind() {
		case reflect.Struct:
			var fieldNum = reflect.ValueOf(param).NumField()
			args = make([]interface{}, 0, fieldNum)
			for i := 0; i < fieldNum; i++ {
				args = append(args, reflect.ValueOf(param).Field(i).Interface())
			}
		case reflect.Map:
			//1、执行指令型判断-根据是否有变量等内容，处理初级SQL
			//TODO 很复杂
			//2、SQL拼接处理，寻找${}的字段，全局替换
			var reg2 = regexp.MustCompile(`\$\{[A-Za-z]+[0-9A-Za-z_\ ]*\}`)
			var strs2 = reg2.FindAllString(execsql,-1)
			//fmt.Println(strs3)
			for _,s := range strs2 {
				var key = s[2:len(s)-1]
				var v = param.(map[string]interface{})[key]
				switch reflect.TypeOf(v).Kind() {
				case reflect.Int, reflect.Int8, reflect.Int16,
					reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8,
					reflect.Uint16, reflect.Uint32, reflect.Uint64:
					execsql = strings.Replace(execsql,s,strconv.FormatInt(int64(v.(int)),10),1)
				case reflect.Float32, reflect.Float64:
					execsql = strings.Replace(execsql,s,strconv.FormatFloat (v.(float64),'E',-1,64),1)
				case reflect.String, reflect.Slice:
					execsql = strings.Replace(execsql,s,string(v.(string)),1)
				default:
					logger.Error("其他类型的SCANER暂不支持v.Kind()[" + reflect.TypeOf(v).Kind().String() + "]")
					panic(errors.New("其他类型的SCANER暂不支持v.Kind()[" + reflect.TypeOf(v).Kind().String() + "]"))
				}
			}
			//3、参数处理，寻找#{}的字段，替换为占位符，组装参数
			var reg3 = regexp.MustCompile(`\#\{[A-Za-z]+[0-9A-Za-z_\ ]*\}`)
			var strs3 = reg3.FindAllString(execsql,-1)
			//fmt.Println(strs3)
			for _,s := range strs3 {
				var key = s[2:len(s)-1]
				execsql = strings.Replace(execsql,s,"?",1)
				var v = param.(map[string]interface{})[key]
				args = append(args, v)
			}
		case reflect.Slice, reflect.Array:
			var params = param.([]interface{})
			args = make([]interface{}, 0, len(params))
			for _, v := range params {
				args = append(args, v)
			}
		default:
			logger.Error("参数组装错误param.Kind()[" + reflect.TypeOf(param).Kind().String() + "]")
			return "",nil, errors.New("参数组装错误param.Kind()[" + reflect.TypeOf(param).Kind().String() + "]")
		}
	}
	//TRIM
	execsql = StringUtils.Trim(execsql)
	logger.Debug("parsesql:    " + execsql)
	logger.Debug("args    :    " + fmt.Sprint(args))
	return execsql,args,nil
}